package com.wgtgt.code_gen;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;

/**
 * Hello world!
 *
 */
public class App {
	public static void main(String[] args) {
		System.out.println("Hello World!");
		String path = "C:\\work\\code_gen\\src\\main\\java\\com\\wgtgt\\code_gen\\code.txt";
		List<String> readUtf8Lines = FileUtil.readUtf8Lines(path);
		String type = null;
		String key = null;
		String value = null;
		String clazz = null;
		int n = 0;
		for (int i = 0; i < readUtf8Lines.size(); i++) {
			String line = readUtf8Lines.get(i);
			line = StrUtil.trim(line);
			if (StrUtil.isBlank(line)) {
				continue;
			}
			if (line.startsWith("#")) {
				continue;
			}
			if (line.contains(":")) {
				if (line.contains("list:") || line.contains("map:")) {
					String left = StrUtil.subBefore(line, ":", false);
					String right = StrUtil.subAfter(line, ":", false);
					clazz = right;
					if (clazz == null || "".equals(clazz)) {
						throw new RuntimeException("类的名字不能为空!");
					}
					left = StrUtil.trim(left);
					right = StrUtil.trim(right);
					if ("list".equals(left) || "list:".equals(left)) {
						type = "list";
						continue;
					}
					if ("map".equals(left) || "map:".equals(left)) {
						type = "map";
						continue;
					}
				}
			}
			if (n == 0) {
				key = line;
				n++;
			} else {
				value = line;
			}
		}
		String code = gen(key, value, type, clazz);
		System.out.println(code);
	}

	private static String gen(String key, String value, String type, String clazz) {
		String resultType = resultType(value);
		if ("list".equals(type)) {
			if("list".equals(resultType)) {
				return genListReturnList(key, value, clazz);
			}else {
				return genListReturnMap(key, value, clazz);
			}
		}
		if ("map".equals(type)) {
			if("list".equals(resultType)) {
				return genMapReturnList(key, value, clazz);
			}else {
				return genMapReturnMap(key, value, clazz);
			}
		}
		throw new RuntimeException("类型不支持!");
	}

	private static String genListReturnList(String key, String value, String clazz) {
		String nl = "\n";
		String tab = "    ";
		String classParam = StrUtil.lowerFirst(clazz);
		String classParamUpper = StrUtil.upperFirst(clazz);
		Map<String, String> mapKey = genMap(key);
		String resultType = resultType(value);
		String typeKey = mapKey.get("type");
		String paramKey = mapKey.get("param");
		String listKey = mapKey.get("list");
		String methodKey = mapKey.get("method");
		StringBuilder sb = new StringBuilder();
		sb.append(tab + "public static ");
		sb.append("List<");
		sb.append(typeKey);
		sb.append(">");
		sb.append(" ");
		sb.append("combination");
		sb.append(classParamUpper);
		sb.append("List");
		sb.append("(");
		sb.append("List<");
		sb.append(clazz);
		sb.append(">");
		sb.append(" ");
		sb.append(listKey);
		sb.append(") {" + nl);
		sb.append(tab + tab + "List<");
		sb.append(typeKey);
		sb.append("> ");
		sb.append("list = new ArrayList<");
		sb.append(typeKey);
		sb.append(">();" + nl);
		sb.append(tab + tab + "for(int i = 0; i < ");
		sb.append(listKey + ".size()");
		sb.append("; i++) {" + nl);
		sb.append(tab + tab + tab + clazz + " ");
		sb.append(classParam + " = ");
		sb.append(listKey + ".");
		sb.append("get(i);" + nl);
		sb.append(tab + tab + tab + "if(");
		sb.append(classParam + " != null) {" + nl);
		sb.append(tab + tab + tab + tab + typeKey + " ");
		sb.append(paramKey + " = ");
		sb.append(classParam + ".");
		sb.append(methodKey + "();" + nl);
		sb.append(tab + tab + tab + tab + "list.add(");
		sb.append(paramKey);
		sb.append(");" + nl);
		sb.append(tab + tab + tab + "}" + nl);
		sb.append(tab + tab + "}" + nl);
		sb.append(tab + tab + "return list;" + nl);
		sb.append(tab + "}" + nl);
		return sb.toString();
	}

	private static String genListReturnMap(String key, String value, String clazz) {
		String nl = "\n";
		String tab = "    ";
		String classParam = StrUtil.lowerFirst(clazz);
		String classParamUpper = StrUtil.upperFirst(clazz);
		Map<String, String> mapKey = genMap(key);
		Map<String, String> mapValue = genMap(value);
		String resultType = resultType(value);
		String typeKey = mapKey.get("type");
		String paramKey = mapKey.get("param");
		String listKey = mapKey.get("list");
		String methodKey = mapKey.get("method");
		String typeValue = mapValue.get("type");
		String paramValue = mapValue.get("param");
		String listValue = mapValue.get("list");
		String methodValue = mapValue.get("method");
		StringBuilder sb = new StringBuilder();
		sb.append(tab + "public static ");
		sb.append("Map<");
		sb.append(typeKey);
		sb.append(", ");
		sb.append(clazz);
		sb.append(">");
		sb.append(" ");
		sb.append("combination");
		sb.append(classParamUpper);
		sb.append("Map");
		sb.append("(");
		sb.append("List<");
		sb.append(clazz);
		sb.append(">");
		sb.append(" ");
		sb.append(listKey);
		sb.append(") {" + nl);
		sb.append(tab + tab);
		sb.append("Map<");
		sb.append(typeKey);
		sb.append(", ");
		sb.append(clazz);
		sb.append(">");
		sb.append(" ");
		sb.append("map = new HashMap<");
		sb.append(typeKey);
		sb.append(", ");
		sb.append(clazz);
		sb.append(">();" + nl);
		sb.append(tab + tab + "for(int i = 0; i < ");
		sb.append(listKey + ".size()");
		sb.append("; i++) {" + nl);
		sb.append(tab + tab + tab + clazz + " ");
		sb.append(classParam + " = ");
		sb.append(listKey + ".");
		sb.append("get(i);" + nl);
		sb.append(tab + tab + tab + "if(");
		sb.append(classParam + " != null) {" + nl);
		sb.append(tab + tab + tab + tab + typeKey + " ");
		sb.append(paramKey + " = ");
		sb.append(classParam + ".");
		sb.append(methodKey + "();" + nl);
		sb.append(tab + tab + tab + tab + "map.put(");
		sb.append(paramKey);
		sb.append(", ");
		sb.append(classParam);
		sb.append(");" + nl);
		sb.append(tab + tab + tab + "}" + nl);
		sb.append(tab + tab + "}" + nl);
		sb.append(tab + tab + "return map;" + nl);
		sb.append(tab + "}" + nl);
		return sb.toString();
	}

	private static String genMapReturnList(String key, String value, String clazz) {
		String nl = "\n";
		String tab = "    ";
		String keyType = "Integer";
		String classParam = StrUtil.lowerFirst(clazz);
		String classParamUpper = StrUtil.upperFirst(clazz);
		Map<String, String> mapKey = genMap(key);
		String resultType = resultType(value);
		String typeKey = mapKey.get("type");
		String paramKey = mapKey.get("param");
		String listKey = mapKey.get("list");
		String methodKey = mapKey.get("method");
		StringBuilder sb = new StringBuilder();
		sb.append(tab + "public static ");
		sb.append("List<");
		sb.append(typeKey);
		sb.append(">");
		sb.append(" ");
		sb.append("combination");
		sb.append(classParamUpper);
		sb.append("Map");
		sb.append("(");
		sb.append("Map<");
		sb.append(keyType);
		sb.append(", ");
		sb.append(clazz);
		sb.append(">");
		sb.append(" ");
		sb.append(listKey);
//		sb.append(listKey);
		sb.append(") {" + nl);
		sb.append(tab + tab + "List<");
		sb.append(typeKey);
		sb.append("> ");
		sb.append("list = new ArrayList<");
		sb.append(typeKey);
		sb.append(">();" + nl);
		sb.append(tab + tab);
		sb.append("List<");
		sb.append("Entry<");
		sb.append(keyType);
		sb.append(", ");
		sb.append(clazz);
		sb.append(">");
		sb.append(">");
		sb.append(" ");
		sb.append("entryList = ");
		sb.append("new ArrayList<");
		sb.append("Entry<");
		sb.append(keyType);
		sb.append(", ");
		sb.append(clazz);
		sb.append(">");
		sb.append(">(");
		sb.append(listKey);
		sb.append(".entrySet()");
		sb.append(");");
		sb.append(nl);
		sb.append(tab + tab + "for(int i = 0; i < ");
		sb.append("entryList");
		sb.append(".size()");
		sb.append("; i++) {" + nl);
		sb.append(tab + tab + tab + "Entry<");
		sb.append(keyType);
		sb.append(", ");
		sb.append(clazz);
		sb.append("> ");
		sb.append(classParam);
		sb.append("Entry");
		sb.append(" = ");
		sb.append("entryList");
		sb.append(".");
		sb.append("get(i);" + nl);
		sb.append(tab + tab + tab + clazz + " ");
		sb.append(classParam + " = ");
		sb.append(classParam);
		sb.append("Entry");
		sb.append(".");
		sb.append("getValue();" + nl);
		sb.append(tab + tab + tab + "if(");
		sb.append(classParam + " != null) {" + nl);
		sb.append(tab + tab + tab + tab + typeKey + " ");
		sb.append(paramKey + " = ");
		sb.append(classParam + ".");
		sb.append(methodKey + "();" + nl);
		sb.append(tab + tab + tab + tab + "list.add(");
		sb.append(paramKey);
		sb.append(");" + nl);
		sb.append(tab + tab + tab + "}" + nl);
		sb.append(tab + tab + "}" + nl);
		sb.append(tab + tab + "return list;" + nl);
		sb.append(tab + "}" + nl);
		return sb.toString();
	}

	private static String genMapReturnMap(String key, String value, String clazz) {
		// TODO Auto-generated method stub
		return null;
	}

	private static String genMap(String key, String value, String clazz) {
		String nl = "\n";
		String tab = "    ";
		String classParam = StrUtil.lowerFirst(clazz);
		Map<String, String> mapKey = genMap(key);
		Map<String, String> mapValue = null;
		String resultType = resultType(value);
		if ("list".equals(resultType)) {
			mapValue = null;
		}
		String typeKey = mapKey.get("type");
		String paramKey = mapKey.get("param");
		String listKey = mapKey.get("list");
		String methodKey = mapKey.get("method");
		String typeValue = null;
		String paramValue = null;
		String listValue = null;
		String methodValue = null;
		if (!"list".equals(resultType)) {
			typeValue = mapValue.get("type");
			paramValue = mapValue.get("param");
			listValue = mapValue.get("list");
			methodValue = mapValue.get("method");
		}

		StringBuilder sb = new StringBuilder();
		sb.append(tab + "public static ");
		sb.append("List<");
		sb.append(typeKey);
		sb.append(">");
		sb.append(" ");
		sb.append("combination");
		sb.append(StrUtil.upperFirst(resultType));
		sb.append("(");
		if ("list".equals(resultType)) {
			sb.append("List<");
			sb.append(clazz);
			sb.append(">");
			sb.append(" ");
			sb.append(listKey);
		} else if ("map".equals(resultType)) {
			sb.append(tab + "for(int i = 0;i < ");
		}
		sb.append(") {" + nl);
		if ("list".equals(resultType)) {
			sb.append(tab + tab + "List<");
			sb.append(typeKey);
			sb.append("> ");
			sb.append("list = new ArrayList<");
			sb.append(typeKey);
			sb.append(">();" + nl);
		} else if ("map".equals(resultType)) {
			sb.append(tab + "for(int i = 0;i < ");
		}
		sb.append(tab + tab + "for(int i = 0; i < ");
		sb.append(listKey + ".size()");
		sb.append(";i++) {" + nl);
		sb.append(tab + tab + tab + clazz + " ");
		sb.append(classParam + " = ");
		sb.append(listKey + ".");
		sb.append("get(i);" + nl);
		sb.append(tab + tab + tab + "if(");
		sb.append(classParam + " != null) {" + nl);
//		sb.append(tab + tab + tab + "" + nl);
//		sb.append(tab + "" + nl);
		sb.append(tab + tab + tab + tab + typeKey + " ");
		sb.append(paramKey + " = ");
		sb.append(classParam + ".");
		sb.append(methodKey + "();" + nl);
		sb.append(tab + tab + tab + tab + "list.add(");
		sb.append(paramKey);
		sb.append(");" + nl);
		sb.append(tab + tab + tab + "}" + nl);
		sb.append(tab + tab + "}" + nl);
		sb.append(tab + tab + "return list;" + nl);
		sb.append(tab + "}" + nl);
		return sb.toString();
	}

	private static String resultType(String value) {
		if (value == null) {
			return "list";
		}
		return "map";
	}

	private static String genList(String key, String value, String clazz) {
		// TODO Auto-generated method stub
		return null;
	}

	private static Map<String, String> genMap(String code) {
		Map<String, String> analysisMap = analysisMap(code);
		return analysisMap;
	}

	private static Map<String, String> analysisMap(String code) {
		Map<String, String> map = new HashMap<>();
		code = StrUtil.trim(code);
		if (code.endsWith(";")) {
			code = code.substring(0, code.length() - 1);
		}
		String left = StrUtil.subBefore(code, "=", false);
		String right = StrUtil.subAfter(code, "=", false);
		left = StrUtil.trim(left);
		right = StrUtil.trim(right);
		left = left.replaceAll("\\s+", " ");
		String type = StrUtil.subBefore(left, " ", false);
		String param = StrUtil.subAfter(left, " ", false);
		type = StrUtil.trim(type);
		param = StrUtil.trim(param);
		String list = StrUtil.subBefore(right, ".", false);
		String method = StrUtil.subAfter(right, ".", false);
		list = StrUtil.trim(list);
		method = StrUtil.trim(method);
		map.put("type", type);
		map.put("param", param);
		map.put("list", list);
		map.put("method", method);
		return map;
	}
}
